﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Audio;

namespace Tetris_AntiGravity
{
    public class Tablero
    {
        //ancho y alto del tablero
        public Int32 ANCHO = 10;
        public Int32 ALTO = 17;
        private Int32 NUM_BLOQUES = 4;

        //almacena los bloques jugados en el tablero
        public int[,] tablero;

        //posicion del tablero en pantalla
        public Vector2 posicion;

        //tamaño en pixeles de cada bloque
        public Int32 tamanoBloque = 32;

        //figura que se esta jugando actualmente
        public Figura figuraActual;

        //proxima figura a jugar;
        public Figura figuraSiguiente;

        //relojes para el manejo del tiempo de actualización
        private float reloj;
        private float relojSubida;

        //manejo de la velocidad de subida de las figuras
        public float velocidadSubida = 0.5f;

        public int puntaje=0;
        public int bombas = 0;
        public int temblor = 0;
        public int sumaLineas = 0;
        public Boolean tableroTerminado = false;

        private Game game;

        private Boolean ponerGranada = false;
        private Boolean ponerGranadaOponente = false;
        private Boolean ponerTornado = false;
        private Boolean ponerTornadoOponente = false;
        private int timeSinceLastFrameGranada = 0;
        private int timeSinceLastFrameGranadaOponente = 0;
        private int frameTornado = 0;
        private int frameTornadoOponente = 0;
        private Sprite granadaSprite;
        private Sprite granadaOponenteSprite;
        private Sprite tornadoSprite;
        private Sprite tornadoOponenteSprite;

        private SoundEffect granadaSound;
        private SoundEffect agregarLineaSound;
        private SoundEffect destruccionSound;
        private SoundEffect tornadoSound;


        //constructor
        public Tablero(Vector2 posicion, Game game)
        {
            this.posicion = posicion;
            this.tablero = new int[ANCHO, ALTO];
            this.game = game;
            this.figuraActual = new Figura(game);
            this.figuraSiguiente = new Figura(game);
            Texture2D texturaGranada = game.Content.Load<Texture2D>(@"assets/este");
            granadaSprite = new AutomatedSprite(texturaGranada, 
                                            new Vector2(posicion.X-50, posicion.Y+50),
                                            new Point(410, 341), 
                                            0, 
                                            new Point(0, 0), 
                                            new Point(5, 0),
                                            Vector2.Zero,
                                            1000
                                            );

            
            granadaOponenteSprite = new AutomatedSprite(texturaGranada,
                                            new Vector2(800, posicion.Y + 50),
                                            new Point(410, 341),
                                            0,
                                            new Point(0, 0),
                                            new Point(5, 0),
                                            Vector2.Zero,
                                            1000
                                            );


            Texture2D texturaTornado = game.Content.Load<Texture2D>(@"assets/tornado");
            
            tornadoSprite = new AutomatedSprite(texturaTornado,
                                            new Vector2(posicion.X - 50, posicion.Y + 50),
                                            new Point(363, 458),
                                            0,
                                            new Point(0, 0),
                                            new Point(4, 0),
                                            Vector2.Zero,
                                            1000
                                            );

            tornadoOponenteSprite = new AutomatedSprite(texturaTornado,
                                            new Vector2(800, posicion.Y + 50),
                                            new Point(363, 458),
                                            0,
                                            new Point(0, 0),
                                            new Point(4, 0),
                                            Vector2.Zero,
                                            1000
                                            );


            granadaSound = game.Content.Load<SoundEffect>(@"sonidos/grahumo");
            agregarLineaSound = game.Content.Load<SoundEffect>(@"sonidos/lineamasomenos");
            destruccionSound = game.Content.Load<SoundEffect>(@"sonidos/destlinea");
            tornadoSound = game.Content.Load<SoundEffect>(@"sonidos/tornado");


            //llenarFilas();

        }

        private void llenarFilas()
        {
            for (int i = 0; i < ANCHO-1; i++)
            {
                for (int j = 0; j < 2; j++)
                {
                    tablero[i, j] = 1;
                }
            }

            //tablero[0, 0] = 0;

        }

        //sube la ficha en el tablero
        public void subir()
        {

            figuraActual.posicion.Y -= 1;
            if (verificarColision(figuraActual))
                figuraActual.posicion.Y += 1;
        }

        public void rotarFicha()
        {
            figuraActual.rotacion++;
            if (figuraActual.rotacion > 3)
                figuraActual.rotacion = 0;
            if (verificarColision(figuraActual))
            {
                figuraActual.rotacion--;
                if (figuraActual.rotacion < 0)
                    figuraActual.rotacion = 3;
            }
        }

        //crea una figura nueva para jugar con ella
        public void crearNuevaFigura()
        {
            //si la figura siguiente no se ha creado, se crea
            if (figuraSiguiente.tipo == TipoFigura.Ninguna)
            {
                figuraSiguiente.tipo = figuraSiguiente.seleccionarFigura();
            }

            //hace la figura actual igual a la siguiente
            figuraActual.tipo = figuraSiguiente.tipo;

            //se genera una nueva figura siguiente
            figuraSiguiente.tipo = figuraSiguiente.seleccionarFigura();

            figuraActual.posicion.X = 4;
            figuraActual.posicion.Y = 13;
            figuraActual.rotacion = 0;


        }

        public void update(GameTime gameTime)
        {
            moverArriba(gameTime);

            if (ponerGranada)
            {
                timeSinceLastFrameGranada -= gameTime.ElapsedGameTime.Milliseconds;
                if (timeSinceLastFrameGranada > 0)
                {
                    granadaSprite.Update(gameTime, game.Window.ClientBounds);
                }

                else if (timeSinceLastFrameGranada < 0)
                {
                    ponerGranada = false;
                    timeSinceLastFrameGranada = 0;
                }
                
            }

            if (ponerGranadaOponente)
            {
                timeSinceLastFrameGranadaOponente -= gameTime.ElapsedGameTime.Milliseconds;
                if (timeSinceLastFrameGranadaOponente > 0)
                {
                    granadaOponenteSprite.Update(gameTime, game.Window.ClientBounds);
                }

                else if (timeSinceLastFrameGranadaOponente < 0)
                {
                    ponerGranadaOponente = false;
                    timeSinceLastFrameGranadaOponente = 0;
                }

            }


            if (ponerTornado)
            {
                if (frameTornado < 4)
                {
                    tornadoSprite.Update(gameTime, game.Window.ClientBounds);
                    frameTornado++;
                }
                else
                {
                    frameTornado = 0;
                    ponerTornado = false;
                }

            }

            if (ponerTornadoOponente)
            {
                if (frameTornadoOponente < 10)
                {
                    tornadoOponenteSprite.Update(gameTime, game.Window.ClientBounds);
                    frameTornadoOponente++;
                }
                else
                {
                    frameTornadoOponente = 0;
                    ponerTornadoOponente = false;
                }

            }
            

            int cantidad = verificarFilas();

            if (cantidad != 0)
            {

                if (cantidad == 2)
                    sumaLineas++;
                if (cantidad == 3)
                    temblor++;
                if (cantidad == 4)
                    bombas++;
                puntaje += cantidad;
            }



            
        }

        public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
        {

            


            
            Texture2D SimpleTexture = new Texture2D(game.GraphicsDevice, 1, 1, false, SurfaceFormat.Color);

            Int32[] pixel = { 0xFFFFFF }; // White. 0xFF is Red, 0xFF0000 is Blue
            SimpleTexture.SetData<Int32>(pixel, 0, SimpleTexture.Width * SimpleTexture.Height);
            /*
            //Crea el borde superior
            spriteBatch.Draw(SimpleTexture, new Rectangle((int)posicion.X, (int)posicion.Y, ANCHO * tamanoBloque, 1), Color.Red);
            //Crea el borde inferior
            spriteBatch.Draw(SimpleTexture, new Rectangle((int)posicion.X, (int)posicion.Y + (ALTO * tamanoBloque), ANCHO * tamanoBloque, 1), Color.Red);
            //Crea El borde izquierdo
            spriteBatch.Draw(SimpleTexture, new Rectangle((int)posicion.X, (int)posicion.Y, 1, ALTO * tamanoBloque), Color.Red);
            //Crea el borde derecho
            spriteBatch.Draw(SimpleTexture, new Rectangle((int)posicion.X + (ANCHO * tamanoBloque), (int)posicion.Y, 1, ALTO * tamanoBloque), Color.Red);
            */
            
            
            for (Int32 aXPosicion = 0; aXPosicion < ANCHO; aXPosicion++)
            {
                for (Int32 aYPosicion = 0; aYPosicion < ALTO; aYPosicion++)
                {
                    Int32 aPositionX = (Int32)(posicion.X + (aXPosicion * tamanoBloque));
                    Int32 aPositionY = (Int32)(posicion.Y + (aYPosicion * tamanoBloque));

                    Texture2D bloque = game.Content.Load<Texture2D>(@"bloques/gris");

                    if ((tablero[aXPosicion, aYPosicion] > 0))
                    {
                        spriteBatch.Draw(bloque, new Rectangle(aPositionX, aPositionY, tamanoBloque, tamanoBloque),
                            null, Color.White);

                    }
                    
                }
            }

            figuraActual.Draw(new Vector2(posicion.X + (Convert.ToInt32(figuraActual.tamanoBloque) * (Int32)figuraActual.posicion.X),
                     posicion.Y + (Convert.ToInt32(figuraActual.tamanoBloque) * (Int32)figuraActual.posicion.Y)), spriteBatch);

            if (ponerGranada)
            {
                granadaSprite.Draw(gameTime, spriteBatch);
            }

            if (ponerGranadaOponente)
                granadaOponenteSprite.Draw(gameTime, spriteBatch);

            if (ponerTornado)
            {
                tornadoSprite.Draw(gameTime, spriteBatch);
            }

            if (ponerTornadoOponente)
            {
                tornadoOponenteSprite.Draw(gameTime, spriteBatch);
            }


            


            Texture2D texturaMenu = game.Content.Load<Texture2D>(@"assets/menu");
            spriteBatch.Draw(texturaMenu, new Vector2(580, 620), Color.White);

        }

        //Mueve la ficha una posición a la Derecha
        internal void moverDerecha()
        {
            figuraActual.posicion.X += 1;
            if (verificarColision(figuraActual))
                figuraActual.posicion.X -= 1;
        }

        //Mueve la ficha una posición a la Derecha
        internal void moverIzquierda()
        {
            figuraActual.posicion.X -= 1;
            if (verificarColision(figuraActual))
                figuraActual.posicion.X += 1;
        }

        //Verificar si la figura actual ha colisionado con algo
        public bool verificarColision(Figura _figura)
        {
            for (int aBloque = 0; aBloque < NUM_BLOQUES; aBloque++)
            {
                // verificar que la figura no se salga de los límites del área del juego ( a la izquierda)
                if (_figura.posicion.X < 0)
                {
                    return true;
                }
                
                //Verificar que la figura no se salga de los límites del área de juego ( a la derecha y abajo)
                if (((_figura.posicion.X + _figura.FiguraActual[_figura.rotacion, aBloque, 0] > ANCHO - 1)
                    | (_figura.posicion.Y + _figura.FiguraActual[_figura.rotacion, aBloque, 1] < 0 )))
                {
                    return true;
                }

                

                //verifica que no se encuentre con un bloque lleno
                if ((tablero[
                    (Int32)_figura.posicion.X + _figura.FiguraActual[_figura.rotacion, aBloque, 0],
                    (Int32)_figura.posicion.Y + _figura.FiguraActual[_figura.rotacion, aBloque, 1]] > 0))
                {

                    //si la posicón Y de la figura es mayor de 0, significa que el juego ha terminado
                    if (_figura.posicion.Y >= 12)
                    {
                        tableroTerminado = true;
                    } 
                    return true;
                }
            }
            return false;
        }

        public void moverArriba(GameTime gameTime)
        {
            relojSubida += (float)gameTime.ElapsedGameTime.TotalSeconds;
            if (relojSubida < velocidadSubida)
                return;

            relojSubida = 0f;
            figuraActual.posicion.Y--;

            if (verificarColision(figuraActual))
            {
                if (figuraActual.posicion.Y >= ALTO * tamanoBloque)
                {
                    return;
                }
                adicionarFigura(figuraActual);
                crearNuevaFigura();
            }
        }

        

        public void adicionarFigura(Figura _figura)
        {
            for (int aBloque = 0; aBloque < NUM_BLOQUES; aBloque++)
            {
                tablero[
                    (Int32)_figura.posicion.X + _figura.FiguraActual[_figura.rotacion, aBloque, 0],
                    (Int32)_figura.posicion.Y + _figura.FiguraActual[_figura.rotacion, aBloque, 1]+1] = 1;
            }
        }

        public int verificarFilas()
        {
            Int32 aNumeroDeLineasLimpiadas = 0;
            

            for (Int32 aPosicionY = 0; aPosicionY < ALTO; aPosicionY ++)
            {
                // Verificar si la fila esta llena en la Posición Y actual
                Boolean lineacompleta = true;
                for (Int32 aXPosition = 0; (aXPosition < ANCHO) && (lineacompleta!=false); aXPosition++)
                {
                    // Si una Posicion.X no se encuentra vacia (menor a 0) entonces la fila se encuentra llena
                    if (tablero[aXPosition, aPosicionY] == 0)
                    {
                        lineacompleta = false;
                        
                    }
                }

                
                // Si la fila esta llena, entonces se elimina la fila
                if (lineacompleta == true)
                {
                    int lineasSeguidas= verificarLineasSeguidas(aPosicionY);


                    for (int i = 1; i <= lineasSeguidas; i++)
                    {
                        for (Int32 aY = aPosicionY; aY < ALTO - 1; aY++)
                        {
                            for (Int32 aX = 0; aX < ANCHO; aX++)
                            {
                                // Mueven todas las filas hacia arriba
                                tablero[aX, aY] = tablero[aX, aY + 1];
                            }
                        }
                    }

                    // Se resetea la fila inferior
                    for (Int32 aX = 0; aX < ANCHO; aX++)
                    {
                        tablero[aX, ALTO-1] = 0;
                    }

                    aNumeroDeLineasLimpiadas += lineasSeguidas;
                }
            }
            return aNumeroDeLineasLimpiadas;
        }

        int verificarLineasSeguidas(int pos)
        {
            Boolean lineacompleta = true;
            int cantidadLineas = 0;

            for (Int32 aPosicionY = pos; aPosicionY < ALTO && (lineacompleta != false); aPosicionY++)
            {
                // Verificar si la fila esta llena en la Posición Y actual
                
                for (Int32 aXPosition = 0; (aXPosition < ANCHO) && (lineacompleta != false); aXPosition++)
                {
                    // Si una Posicion.X no se encuentra vacia (menor a 0) entonces la fila se encuentra llena
                    if (tablero[aXPosition, aPosicionY] == 0)
                    {
                        lineacompleta = false;

                    }
                }

                if (lineacompleta)
                {
                    cantidadLineas++;
                    destruccionSound.Play();
                }
            }

            return cantidadLineas;
        }

        public void agregarLinea() {

            agregarLineaSound.Play();

            for (int y = ALTO - 1; y > 0; y--)
            {
                for (int x = 0; x < ANCHO; x++)
                {
                    tablero[x, y] = tablero[x, y-1];
                }
                for (int x = 0; x < ANCHO; x++)
                {
                    tablero[x, 0] = 0;
                }
            }
        }

        public void eliminarLinea()
        {
            agregarLineaSound.Play();
            
            for (int y = 0; y < ALTO-1; y++)
            {
                for (int x = 0; x < ANCHO; x++)
                {
                    tablero[x, y] = tablero[x, y + 1];
                }
                
            }
        }

        public void lanzarTornado()
        {
            Random mRandom = new Random(DateTime.Now.Millisecond);

            ponerTornado = true;

            tornadoSound.Play();

            for (int i = 1; i <= 5; i++)
            {
                int x = mRandom.Next(ANCHO - 1);
                int y = mRandom.Next(ALTO - 1);
                if (tablero[x, y] == 1)
                    tablero[x, y] = 0;
                else
                    tablero[x, y] = 1;
            }
        }

        public void lanzarTornadoOponente()
        {
            tornadoSound.Play();
            ponerTornadoOponente = true;

        }

        public void lanzarBomba()
        {
            granadaSound.Play();
                ponerGranada = true;
                timeSinceLastFrameGranada = 15000;
                //bombas--;
        }

        public void lanzarBombaOponente()
        {
            granadaSound.Play();
            ponerGranadaOponente = true;
            timeSinceLastFrameGranadaOponente = 15000;
            
        }

    }
}
